package com.zzh.wxdemo;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Looper;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;

import com.alibaba.fastjson.JSON;
import com.zzh.wxdemo.bean.ColumnBean;
import com.zzh.wxdemo.config.ShellTag;
import com.zzh.wxdemo.utils.MessageDigestUtils;
import com.zzh.wxdemo.utils.ShellUtils;
import com.zzh.wxdemo.utils.SysytemUtils;
import com.zzh.wxdemo.utils.ToastUtil;

import net.sqlcipher.Cursor;
import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteDatabaseHook;


import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static net.sqlcipher.database.SQLiteDatabase.NO_LOCALIZED_COLLATORS;

public class MainActivity extends AppCompatActivity {

    private String TAG = "zzh";

    private String permissions[] = new String[]{
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE
    };

    private String mUin;
    private String mImei;
    private String mPass;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.db_file).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (TextUtils.isEmpty(mUin)) {
                    ToastUtil.show("请获取UIN");
                    return;
                }
                String dbFile = MessageDigestUtils.md5("mm" + mUin).toLowerCase();
                Log.i(TAG, ">>>dbFile>>>" + dbFile);
            }
        });
        findViewById(R.id.copy).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Looper.prepare();
                        copyEnMicroMsgDb();
                        Looper.loop();
                    }
                }).start();
            }
        });
        findViewById(R.id.read_imei).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mImei = SysytemUtils.getIMEI(MainActivity.this);
                if (TextUtils.isEmpty(mImei)) {
                    mImei = "1234567890ABCDEF";
                } else {
                    ToastUtil.show("获取IMEI成功");
                }
            }
        });
        findViewById(R.id.pass).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mPass = generatePass();
                Log.i(TAG, ">>>pass>>>>" + mPass);
            }
        });
        findViewById(R.id.read_database).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                    readData();
//                test(ColumnBean.tablesName);
//                new Thread(new Runnable() {
//                    @Override
//                    public void run() {
//                        Looper.prepare();
//                        selectWhereValue(ColumnBean.tablesName, "啦啦啦");
//                        Looper.loop();
//                    }
//                }).start();

            }
        });
    }


    private void selectWhereValue(String sqlNames[], String value) {
        if (TextUtils.isEmpty(mPass)) {
            ToastUtil.show("请获取密码");
            return;
        }
        Log.i(TAG, "start");
        SQLiteDatabase.loadLibs(MainActivity.this);
        SQLiteDatabaseHook hook = new SQLiteDatabaseHook() {
            public void preKey(SQLiteDatabase database) {
            }

            public void postKey(SQLiteDatabase database) {
                database.rawExecSQL("PRAGMA cipher_migrate;");//很重要
            }
        };

        SQLiteDatabase db = SQLiteDatabase.openDatabase(
                MainActivity.this.getFilesDir().getAbsolutePath() + File.separator + ShellTag.FILE_NAME,
                mPass,
                null,
                NO_LOCALIZED_COLLATORS,
                hook);
        List<Map<String, Object>> mapList = new ArrayList<>();
        for (int i = 0; i < sqlNames.length; i++) {
            Cursor c = db.rawQuery(String.format("select * from %s;", sqlNames[i]), null);
            mapList.clear();
            String keys[] = c.getColumnNames();
            while (c.moveToNext()) {
                Map<String, Object> map = new HashMap<>();
                for (int j = 0; j < keys.length; j++) {
                    String key = keys[j];
                    int index = c.getColumnIndex(key);
                    int type = c.getType(index);
                    Object obj = null;
                    switch (type) {
                        case Cursor.FIELD_TYPE_INTEGER:
                            obj = c.getLong(index);
                            break;
                        case Cursor.FIELD_TYPE_STRING:
                            obj = c.getString(index);
                            break;
                        case Cursor.FIELD_TYPE_NULL:
                            obj = c.getString(index);
                            break;
                        case Cursor.FIELD_TYPE_BLOB:
                            obj = c.getBlob(index);
                            break;
                        case Cursor.FIELD_TYPE_FLOAT:
                            obj = c.getDouble(index);
                            break;
                    }
                    map.put(key, obj);
                }
                mapList.add(map);
            }
            c.close();
            String valueSql = JSON.toJSONString(mapList);
            if (!TextUtils.isEmpty(valueSql) && valueSql.contains(value)) {
                Log.i(TAG, ">>i>>>" + sqlNames[i]);
            }
        }
        db.close();
        Log.i(TAG, "stop");
    }

    private void test(String sqls[]) {
        if (TextUtils.isEmpty(mPass)) {
            ToastUtil.show("请获取密码");
            return;
        }
        SQLiteDatabase.loadLibs(MainActivity.this);
        SQLiteDatabaseHook hook = new SQLiteDatabaseHook() {
            public void preKey(SQLiteDatabase database) {
            }

            public void postKey(SQLiteDatabase database) {
                database.rawExecSQL("PRAGMA cipher_migrate;");//很重要
            }
        };

        SQLiteDatabase db = SQLiteDatabase.openDatabase(
                MainActivity.this.getFilesDir().getAbsolutePath() + File.separator + ShellTag.FILE_NAME,
                mPass,
                null,
                NO_LOCALIZED_COLLATORS,
                hook);
        List<ColumnBean> columnBeanList = new ArrayList<>();
        for (int i = 0; i < sqls.length; i++) {
            Cursor c = db.rawQuery(String.format("pragma table_info('%s');", sqls[i]), null);
            columnBeanList.clear();
            while (c.moveToNext()) {
                String name = c.getString(c.getColumnIndex("name"));
                String type = c.getString(c.getColumnIndex("type"));
                ColumnBean columnBean = new ColumnBean();
                columnBean.setName(name);
                columnBean.setType(type);
                columnBeanList.add(columnBean);
            }
            c.close();
            Log.i(TAG, sqls[i] + "=>" + columnBeanList.toString());
        }
        db.close();

    }


    private String generatePass() {
        if (TextUtils.isEmpty(mImei)) {
            ToastUtil.show("请获取IMEI");
            return "";
        }
        if (TextUtils.isEmpty(mUin)) {
            ToastUtil.show("请获取UIN");
            return "";
        }
        Log.i(TAG, ">>imei>>" + mImei + ">>uin>>" + mUin);
        String pass = MessageDigestUtils.md5(mImei + mUin).substring(0, 7).toLowerCase();
        return pass;
    }

    private void readData() {
        if (TextUtils.isEmpty(mPass)) {
            ToastUtil.show("请获取密码");
            return;
        }
        SQLiteDatabase.loadLibs(MainActivity.this);
        SQLiteDatabaseHook hook = new SQLiteDatabaseHook() {
            public void preKey(SQLiteDatabase database) {
            }

            public void postKey(SQLiteDatabase database) {
                database.rawExecSQL("PRAGMA cipher_migrate;");//很重要
            }
        };
        Log.i(TAG, ">>path>>>" + (MainActivity.this.getFilesDir().getAbsolutePath() + File.separator + ShellTag.FILE_NAME));
        SQLiteDatabase db = SQLiteDatabase.openDatabase(
                MainActivity.this.getFilesDir().getAbsolutePath() + File.separator + ShellTag.FILE_NAME,
                mPass,
                null,
                NO_LOCALIZED_COLLATORS,
                hook);
        long now = System.currentTimeMillis();
        Log.e("readWxDatabases", "读取微信数据库:" + now);
        String sql = "select * from message";
        Log.e("sql", sql);
        Cursor c = db.rawQuery(sql, null);
        List<Map<String, Object>> mapList = new ArrayList<>();
        String keys[] = c.getColumnNames();
        while (c.moveToNext()) {
            Map<String, Object> map = new HashMap<>();
            for (int i = 0; i < keys.length; i++) {
                String key = keys[i];
                int index = c.getColumnIndex(key);
                int type = c.getType(index);
                Object obj = null;
                switch (type) {
                    case Cursor.FIELD_TYPE_INTEGER:
                        obj = c.getLong(index);
                        break;
                    case Cursor.FIELD_TYPE_STRING:
                        obj = c.getString(index);
                        break;
                    case Cursor.FIELD_TYPE_NULL:
                        obj = c.getString(index);
                        break;
                    case Cursor.FIELD_TYPE_BLOB:
                        obj = c.getBlob(index);
                        break;
                    case Cursor.FIELD_TYPE_FLOAT:
                        obj = c.getDouble(index);
                        break;
                }
                map.put(key, obj);
            }
            mapList.add(map);
        }
        c.close();
        db.close();
        Log.e("readWxDatanases", "读取结束:" + System.currentTimeMillis() + ",count:" + mapList.size());
        for (int i = 0; i < mapList.size(); i++) {
            Log.i(TAG, ">>>" + JSON.toJSONString(mapList.get(i)));
        }
    }

    private void readUIN() {
        FileInputStream inStream = null;
        ByteArrayOutputStream outStream = null;
        try {
            inStream = MainActivity.this.openFileInput(ShellTag.UIN_FIEL_NAME);
            outStream = new ByteArrayOutputStream();//输出到内存

            int len = 0;
            byte[] buffer = new byte[1024];
            while ((len = inStream.read(buffer)) != -1) {
                outStream.write(buffer, 0, len);//
            }

            byte[] content_byte = outStream.toByteArray();
            String content = new String(content_byte);
            mUin = parsingUIN(content);

            // 复制数据库
            String dbFile = MessageDigestUtils.md5("mm" + mUin).toLowerCase();
            rmTargetEnMicroMsgDb();
            boolean isCp = cpEnMicroMsgDb(dbFile);
            if (isCp) chmodEnMicroMsgDb();
            ToastUtil.show(isCp ? "复制源文件到目标文件夹成功" : "复制源文件到目标文件夹失败");
            Log.i(TAG, ">>content>>\n" + content + "\n" + ">>uin>>" + mUin);


        } catch (FileNotFoundException e) {
            e.printStackTrace();
            ToastUtil.show("读取uin失败");
        } catch (IOException e) {
            e.printStackTrace();
            ToastUtil.show("读取uin失败");
        } finally {
            try {
                if (inStream != null) {
                    inStream.close();
                }
                if (outStream != null) {
                    outStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            inStream = null;
            outStream = null;
        }
    }

    private String parsingUIN(String content) {
        String sp = "name=\"default_uin\" value=\"";
        int index = content.indexOf(sp);
        int startIndex = index + sp.length();
        String uin = content.substring(startIndex, startIndex + 9);
        return uin;
    }


    private List<String> mPermissionList;

    private void applyForPermissions(String permissions[]) {
        mPermissionList = new ArrayList<>();
        for (int i = 0; i < permissions.length; i++) {
            if (ContextCompat.checkSelfPermission(MainActivity.this, permissions[i]) != PackageManager.PERMISSION_GRANTED) {
                mPermissionList.add(permissions[i]);
            }
        }
        if (mPermissionList.isEmpty()) {//未授予的权限为空，表示都授予了
            readUIN();
        } else {//请求权限方法
            String[] noPermissions = mPermissionList.toArray(new String[mPermissionList.size()]);//将List转为数组
            ActivityCompat.requestPermissions(MainActivity.this, noPermissions, MY_PERMISSIONS_REQUEST_CALL_CAMERA);
        }
    }

    private static final int MY_PERMISSIONS_REQUEST_CALL_PHONE = 1;
    private static final int MY_PERMISSIONS_REQUEST_CALL_CAMERA = 2;

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {

        if (requestCode == MY_PERMISSIONS_REQUEST_CALL_PHONE) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                readUIN();
            } else {
                ToastUtil.show("权限已拒绝");
            }
        } else if (requestCode == MY_PERMISSIONS_REQUEST_CALL_CAMERA) {
            for (int i = 0; i < grantResults.length; i++) {
                if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                    //判断是否勾选禁止后不再询问
                    boolean showRequestPermission = ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, permissions[i]);
                    if (showRequestPermission) {
                        ToastUtil.show("权限未申请");
                    }
                }
            }
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }


    private void copyEnMicroMsgDb() {
        rmUINFile();
        boolean isCpUIN = cpSystemConfigPrefsFile();
        if (isCpUIN) chmodSystemConfigPrefsFile();
        else {
            ToastUtil.show("复制UIN到目标文件夹失败");
            return;
        }
        applyForPermissions(permissions);
    }

    private void rmTargetEnMicroMsgDb() {
        String rm = ShellTag.TAG_RM + MainActivity.this.getFilesDir().getAbsolutePath() + File.separator + ShellTag.FILE_NAME;
        ShellUtils.execCommand(rm, true);
    }

    private void rmUINFile() {
        String rm = ShellTag.TAG_RM + MainActivity.this.getFilesDir().getAbsolutePath() + File.separator + ShellTag.UIN_FIEL_NAME;
        ShellUtils.execCommand(rm, true);
    }

    private boolean cpEnMicroMsgDb(String folder) {
        String cp = ShellTag.TAG_CP + ShellTag.SOURCE_PATH + folder + File.separator + ShellTag.FILE_NAME + ShellTag.INTERVAL + MainActivity.this.getFilesDir().getAbsolutePath();
        ShellUtils.CommandResult commandResult = ShellUtils.execCommand(cp, true);
        return commandResult.result == 0;
    }

    private boolean cpSystemConfigPrefsFile() {
        String cp = ShellTag.TAG_CP + ShellTag.UIN_FILE_PATH + File.separator + ShellTag.UIN_FIEL_NAME + ShellTag.INTERVAL + MainActivity.this.getFilesDir().getAbsolutePath();
        ShellUtils.CommandResult commandResult = ShellUtils.execCommand(cp, true);
        return commandResult.result == 0;
    }

    private void chmodEnMicroMsgDb() {
        String chmod = ShellTag.TAG_CHMOD + " 777 " + MainActivity.this.getFilesDir().getAbsolutePath() + File.separator + ShellTag.FILE_NAME;
        ShellUtils.execCommand(chmod, true);
    }

    private void chmodSystemConfigPrefsFile() {
        String chmod = ShellTag.TAG_CHMOD + " 777 " + MainActivity.this.getFilesDir().getAbsolutePath() + File.separator + ShellTag.UIN_FIEL_NAME;
        ShellUtils.execCommand(chmod, true);
    }


}
